<?php

declare(strict_types=1);
/**
 * This file is part of habo_new_media.
 *
 * @link     https://www.berlen.cn/
 * @contact  tech@berlen.cn
 * @license  http://gitlab.rehou.cn/habo/habo_new_media/-/blob/master/README.md
 */

namespace app\service\batch\kuaishou;

use app\enum\CommonEnum;
use app\enum\ConfigEnum;
use app\enum\KuaiShouEnum;
use app\model\mysql\KsTimeFrameLogModel;
use app\model\mysql\KsTimeFrameTaskContentModel;
use app\model\mysql\KsTimeFrameTaskModel;
use app\service\batch\MediaInterface;
use app\service\batch\MediaService;
use app\service\client\AccountService;
use app\service\kuaishou\AdvertiserService;
use think\db\exception\DbException;
use think\Exception;

class UnitTimeFramePushService extends MediaService implements MediaInterface
{
    /**
     * @var string 批量修改的投放时段锁
     */
    protected const BATCH_KEY = ConfigEnum::CACHE_CONFIG[KuaiShouEnum::BATCH_CONFIG_LOCK_KEY]['unit_frame_time_content_push'];

    /**
     * 获取批量修改的快手投放时段.
     * @param int $contentId
     * @return bool
     * @throws DbException
     * @throws Exception
     */
    public static function uintFrameTimeUpdate(int $contentId = 0): bool
    {
        // 修改投放时间记录
        $timeFrameLogModel = (new KsTimeFrameLogModel())->where('content_id', $contentId)->field(true)->findOrEmpty();
        if (! $timeFrameLogModel->getKey()) {
            return self::setError('未知的投放时段记录');
        }
        // 修改投放时间内容
        $timeFrameContentModel = (new KsTimeFrameTaskContentModel())->field(true)->findOrEmpty($contentId);
        if (! $timeFrameContentModel->getKey()) {
            return self::setError('未知的投放时段修改内容');
        }
        if ($timeFrameContentModel->getAttr('status')) {
            return true;
        }
        $timeFrameModel = (new KsTimeFrameTaskModel())->field(true)->findOrEmpty($timeFrameContentModel->getAttr('frame_id'));
        if (! $timeFrameModel->getKey()) {
            return self::setError('未知的投放时段设置内容');
        }
        // 请求参数
        $timeFrame = [];
        $timeFrame['unit_id'] = $timeFrameContentModel->getAttr('unit_id');
        $timeFrame['unit_name'] = $timeFrameContentModel->getAttr('unit_name');
        $timeFrame['advertiser_id'] = $timeFrameModel->getAttr('advertiser_id');
        $timeFrame['schedule_time'] = $timeFrameModel->getAttr('schedule_time') ?? '';
        // 修改请求
        $result = self::updateTimeframe($timeFrame, $timeFrameModel->getAttr('ip_address'));
        if (! $result) {
            // 记录失败日志
            if (! self::setTimeframeFail($timeFrameContentModel, $timeFrameLogModel)) {
                return false;
            }
        } else {
            // 记录成功日志
            if (! self::setTimeframeSuccess($timeFrameContentModel, $timeFrameLogModel, $result)) {
                return false;
            }
        }
        // 更新任务状态,数据
        return self::updateTaskStatus($timeFrameModel);
    }

    /**
     * 修改投放时段.
     * @param array $params 请求参数
     * @param mixed $ipAddress ip
     * @return bool|mixed|string
     */
    private static function updateTimeframe(array $params = [], $ipAddress = '')
    {
        $token = AccountService::getToken(CommonEnum::KS_MEDIA, $params['advertiser_id']);
        if (! $token) {
            return self::setError('token获取失败');
        }
        $headers = [
            'Access-Token' => $token,
            'Content-Type' => 'application/json',
            'K-RealUser-IP' => $ipAddress,
        ];
        return AdvertiserService::updateUnit($headers, $params);
    }

    /**
     * 更新任务状态.
     * @param KsTimeFrameTaskModel $timeFrameModel
     * @return bool
     * @throws DbException
     */
    private static function updateTaskStatus(KsTimeFrameTaskModel $timeFrameModel): bool
    {
        // 更新任务状态
        if (! $timeFrameModel->getAttr('is_pull')) {
            return true;
        }
        $waitNum = (new KsTimeFrameTaskContentModel())->where([
            ['frame_id', '=', $timeFrameModel->getKey()],
            ['status', '=', KsTimeFrameTaskContentModel::STATUS_WAIT],
        ])->count();
        if (! $waitNum) {
            $num = (new KsTimeFrameTaskContentModel())->where('frame_id', $timeFrameModel->getKey())->count();
            $fallNum = (new KsTimeFrameTaskContentModel())->where([
                ['frame_id', '=', $timeFrameModel->getKey()],
                ['status', '=', KsTimeFrameTaskContentModel::STATUS_FAIL],
            ])->count();

            $timeFrameModel->setAttrs([
                'num' => $num,
                'status' => $fallNum > 0 ? (KsTimeFrameTaskModel::STATUS_FAIL) : (KsTimeFrameTaskModel::STATUS_SUCCESS),
            ]);

            if (! $timeFrameModel->save()) {
                return self::setError('设置组出价任务状态失败');
            }
        }
        return true;
    }

    /**
     * 失败记录.
     * @param KsTimeFrameTaskContentModel $timeFrameContentModel
     * @param KsTimeFrameLogModel $timeFrameLogModel
     * @return bool
     */
    private static function setTimeframeFail(KsTimeFrameTaskContentModel $timeFrameContentModel, KsTimeFrameLogModel $timeFrameLogModel): bool
    {
        // 失败记录状态
        $timeFrameContentModel->setAttr('status', KsTimeFrameTaskContentModel::STATUS_FAIL);
        if (! $timeFrameContentModel->save()) {
            return self::setError('保存组投放时间错误状态失败');
        }
        // 失败记录日志
        $timeFrameLogModel->setAttrs([
            'status' => KsTimeFrameLogModel::STATUS_FAIL,
            'error_json' => json_encode([AdvertiserService::getError(0)], JSON_UNESCAPED_UNICODE),
            'error_msg' => AdvertiserService::getError(0),
        ]);
        if (! $timeFrameLogModel->save()) {
            return self::setError('保存投放时间错误结果日志失败');
        }
        return true;
    }

    /**
     * 成功记录.
     * @param KsTimeFrameTaskContentModel $timeFrameContentModel
     * @param KsTimeFrameLogModel $timeFrameLogModel
     * @param array $result 回调参数
     * @return bool
     */
    private static function setTimeframeSuccess(KsTimeFrameTaskContentModel $timeFrameContentModel, KsTimeFrameLogModel $timeFrameLogModel, array $result = []): bool
    {
        // 成功记录状态
        $timeFrameContentModel->setAttr('status', KsTimeFrameTaskContentModel::STATUS_SUCCESS);
        if (! $timeFrameContentModel->save()) {
            return self::setError('保存组投放时间成功状态失败');
        }
        // 成功记录日志
        $timeFrameLogModel->setAttrs([
            'status' => KsTimeFrameLogModel::STATUS_SUCCESS,
            'error_json' => json_encode($result, JSON_UNESCAPED_UNICODE),
            'error_msg' => $result['message'],
        ]);
        if (! $timeFrameLogModel->save()) {
            return self::setError('保存投放时间成功结果日志失败');
        }
        return true;
    }
}
